/*
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "base/resource/ace_res_key_parser.h"

#ifdef WINDOWS_PLATFORM
#include <cstdio>
#else
#include "securec.h"
#endif
#include <algorithm>
#include <functional>
#include <regex>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

#include "base/log/log.h"
#include "base/utils/string_utils.h"

namespace Keels::Ace {
namespace {

constexpr int32_t MCC_MNC_KEYWORD_LEN = 3;
constexpr int32_t MCC_MNC_VALUE_LEN = 3;
constexpr int32_t MAX_MCC_MNC_LEN = 8;

} // namespace

AceResKeyParser::AceResKeyParser() = default;
AceResKeyParser::~AceResKeyParser() = default;

bool AceResKeyParser::Parse(const std::string& deviceResConfigTag, std::vector<KeyParam>& keyParams, bool styleRes)
{
    std::vector<std::string> keyParts;
    StringUtils::StringSplitter(deviceResConfigTag, '-', keyParts);

    static parse_key_function functions[] = {
        ParseMcc,
        ParseMnc,
        ParseOrientation,
        ParseColorMode,
        ParseDeviceType,
        ParseResolution,
        ParseDefaults,
    };
    const int32_t FUNC_LEN = static_cast<int32_t>(sizeof(functions) / sizeof(functions[0]));
    if (!keyParts.empty()) {
        if (!ParseMatch(keyParts, keyParams, functions, FUNC_LEN, styleRes)) {
            LOGW("Invalid config:%{public}s", deviceResConfigTag.c_str());
            return false;
        }
        return true;
    }
    return false;
}

bool AceResKeyParser::DeclarativeParse(const std::string& deviceResConfigTag, std::vector<KeyParam>& keyParams)
{
    std::vector<std::string> reskeyParts;
    std::string resConfigTag(deviceResConfigTag);
    StringUtils::StringSplitter(resConfigTag, '-', reskeyParts);

    static parse_key_function functions[] = {
        ParseLongScreen,
        ParseScreenShape,
        ParseOrientation,
        ParseDeclarativeColorMode,
        ParseDeviceType,
        ParseResolution,
        ParseDefaults,
    };
    const int32_t FUNC_LEN = static_cast<int32_t>(sizeof(functions) / sizeof(functions[0]));
    if (!reskeyParts.empty()) {
        if (!ParseMatch(reskeyParts, keyParams, functions, FUNC_LEN, true)) {
            LOGW("Invalid config:%{public}s", resConfigTag.c_str());
            return false;
        }
        return true;
    }
    return false;
}

bool AceResKeyParser::ParseMatch(const std::vector<std::string>& keys, std::vector<KeyParam>& keyParams,
    parse_key_function functions[], int32_t funcLen, bool styleRes) const
{
    for (auto iter = keys.begin(); iter != keys.end(); iter++) {
        if (iter == keys.begin() && !styleRes) {
            if (*iter == "res") {
                continue;
            } else {
                return false;
            }
        }
        bool parseRet = false;
        for (int32_t k = 0; k < funcLen; k++) {
            if (functions[k](*iter, keyParams)) {
                parseRet = true;
                break;
            }
        }
        if (!parseRet) {
            return false;
        }
    }
    return true;
}

bool AceResKeyParser::ParseMcc(const std::string& key, std::vector<KeyParam>& keyParams)
{
    std::regex mcc("mcc(\\d{3})");
    if (regex_match(key, mcc)) {
        KeyParam keyParam;
        keyParam.value = StringUtils::StringToInt(key.substr(MCC_MNC_KEYWORD_LEN));
        keyParam.keyType = KeyType::MCC;
        keyParams.emplace_back(keyParam);
        return true;
    }
    return false;
}

bool AceResKeyParser::ParseMnc(const std::string& key, std::vector<KeyParam>& keyParams)
{
    std::regex mnc("mnc(\\d{2,3})");
    if (regex_match(key, mnc)) {
        KeyParam keyParam;
        keyParam.value = StringUtils::StringToInt(key.substr(MCC_MNC_KEYWORD_LEN));
        if (key.substr(MCC_MNC_KEYWORD_LEN).length() == MCC_MNC_VALUE_LEN) {
            keyParam.keyType = KeyType::MNC;
        } else {
            keyParam.keyType = KeyType::MNC_SHORT_LEN;
        }
        keyParams.emplace_back(keyParam);
        return true;
    }
    return false;
}

bool AceResKeyParser::ParseScreenShape(const std::string& key, std::vector<KeyParam>& keyParams)
{
    ScreenShape shape;
    if (key == "round")
        shape = ScreenShape::ROUND;
    else if (key == "notround")
        shape = ScreenShape::NOT_ROUND;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::SCREENSHAPE;
    keyParam.value = static_cast<int32_t>(shape);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseLongScreen(const std::string& key, std::vector<KeyParam>& keyParams)
{
    LongScreenType type;
    if (key == "long")
        type = LongScreenType::LONG;
    else if (key == "notlong")
        type = LongScreenType::NOT_LONG;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::LONGSCREEN;
    keyParam.value = static_cast<int32_t>(type);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseOrientation(const std::string& key, std::vector<KeyParam>& keyParams)
{
    DeviceOrientation type;
    if (key == "horizontal")
        type = DeviceOrientation::LANDSCAPE;
    else if (key == "vertical")
        type = DeviceOrientation::PORTRAIT;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::ORIENTATION;
    keyParam.value = static_cast<int32_t>(type);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseColorMode(const std::string& key, std::vector<KeyParam>& keyParams)
{
    ColorMode color;
    if (key == "dark")
        color = ColorMode::DARK;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::COLOR_MODE;
    keyParam.value = static_cast<int32_t>(color);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseDeclarativeColorMode(const std::string& key, std::vector<KeyParam>& keyParams)
{
    ColorMode color;
    if (key == "dark")
        color = ColorMode::DARK;
    else if (key == "light")
        color = ColorMode::LIGHT;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::DECLARATIVE_COLOR_MODE;
    keyParam.value = static_cast<int32_t>(color);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseDeviceType(const std::string& key, std::vector<KeyParam>& keyParams)
{
    DeviceType type;
    if (key == "phone")
        type = DeviceType::PHONE;
    else if (key == "tablet")
        type = DeviceType::TABLET;
    else if (key == "tv")
        type = DeviceType::TV;
    else if (key == "wearable")
        type = DeviceType::WATCH;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::DEVICETYPE;
    keyParam.value = static_cast<int32_t>(type);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseResolution(const std::string& key, std::vector<KeyParam>& keyParams)
{
    ResolutionType type;
    if (key == "ldpi")
        type = ResolutionType::RESOLUTION_LDPI;
    else if (key == "mdpi")
        type = ResolutionType::RESOLUTION_MDPI;
    else if (key == "hdpi")
        type = ResolutionType::RESOLUTION_HDPI;
    else if (key == "xhdpi")
        type = ResolutionType::RESOLUTION_XHDPI;
    else if (key == "xxhdpi")
        type = ResolutionType::RESOLUTION_XXHDPI;
    else if (key == "xxxhdpi")
        type = ResolutionType::RESOLUTION_XXXHDPI;
    else
        return false;

    KeyParam keyParam;
    keyParam.keyType = KeyType::RESOLUTION;
    keyParam.value = static_cast<int32_t>(type);
    keyParams.emplace_back(keyParam);
    return true;
}

bool AceResKeyParser::ParseDefaults(const std::string& key, std::vector<KeyParam>& keyParams)
{
    return key == "defaults" || key == "default";
}

std::string AceResKeyParser::GetMccByValue(uint32_t value) const
{
    char mccStr[MAX_MCC_MNC_LEN] = { 0 };
    if (sprintf_s(mccStr, MAX_MCC_MNC_LEN, "mcc%03u", value) < 0) {
        return "";
    }
    return std::string(mccStr);
}

std::string AceResKeyParser::GetMncShortLenByValue(uint32_t value) const
{
    char mncStr[MAX_MCC_MNC_LEN] = { 0 };
    if (sprintf_s(mncStr, MAX_MCC_MNC_LEN, "mnc%02u", value) < 0) {
        return "";
    }
    return std::string(mncStr);
}

std::string AceResKeyParser::GetMncByValue(uint32_t value) const
{
    char mncStr[MAX_MCC_MNC_LEN] = { 0 };
    if (sprintf_s(mncStr, MAX_MCC_MNC_LEN, "mnc%03u", value) < 0) {
        return "";
    }
    return std::string(mncStr);
}

std::string AceResKeyParser::GetOrientationByType(DeviceOrientation type) const
{
    switch (type) {
        case DeviceOrientation::LANDSCAPE:
            return "horizontal";
        case DeviceOrientation::PORTRAIT:
            return "vertical";
        default:
            return "";
    }
}

std::string AceResKeyParser::GetColorModeByType(ColorMode type) const
{
    switch (type) {
        case ColorMode::DARK:
            return "dark";
        default:
            return "";
    }
}

std::string AceResKeyParser::GetDeclarativeColorModeByType(ColorMode type) const
{
    switch (type) {
        case ColorMode::DARK:
            return "dark";
        case ColorMode::LIGHT:
            return "light";
        default:
            return "";
    }
}

std::string AceResKeyParser::GetDeviceByType(DeviceType type) const
{
    switch (type) {
        case DeviceType::PHONE:
            return "phone";
        case DeviceType::TABLET:
            return "tablet";
        case DeviceType::TV:
            return "tv";
        case DeviceType::WATCH:
            return "wearable";
        default:
            return "";
    }
}

std::string AceResKeyParser::GetResolutionByType(ResolutionType type) const
{
    switch (type) {
        case ResolutionType::RESOLUTION_LDPI:
            return "ldpi";
        case ResolutionType::RESOLUTION_MDPI:
            return "mdpi";
        case ResolutionType::RESOLUTION_HDPI:
            return "hdpi";
        case ResolutionType::RESOLUTION_XHDPI:
            return "xhdpi";
        case ResolutionType::RESOLUTION_XXHDPI:
            return "xxhdpi";
        case ResolutionType::RESOLUTION_XXXHDPI:
            return "xxxhdpi";
        default:
            return "";
    }
}
std::string AceResKeyParser::GetScreenShapeByType(ScreenShape type) const
{
    switch (type) {
        case ScreenShape::ROUND:
            return "round";
        case ScreenShape::NOT_ROUND:
            return "notround";
        default:
            return "";
    }
}

std::string AceResKeyParser::GetScreenLongByType(LongScreenType type) const
{
    switch (type) {
        case LongScreenType::LONG:
            return "long";
        case LongScreenType::NOT_LONG:
            return "notlong";
        default:
            return "";
    }
}

} // namespace Keels::Ace
